﻿using System;
using System.Collections.Generic;

namespace YanZhiwei.DotNet2.Utilities.Common
{
    /// <summary>
    /// Type 帮助类
    /// </summary>
    public static class TypeHelper
    {
        #region 类型是否为空
        /// <summary>
        /// 判断是否为可空类型
        /// <para>eg:TypeHelper.IsNullableType(typeof(int?))==>true</para>
        /// <para>rel:http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html </para>
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns>是否为空</returns>
        public static bool IsNullableType(this Type type)
        {
            return (((type != null) && type.IsGenericType) &&
                (type.GetGenericTypeDefinition() == typeof(Nullable<>)));
        }
        #endregion
        #region 获取对象类型
        /// <summary>
        /// 获取对象类型
        /// <para>eg:TypeHelper.GetNonNullableType(typeof(int?)==>typeof(int)</para>
        /// <para>rel:http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html </para>
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns>Type</returns>
        public static Type GetNonNullableType(this Type type)
        {
            return Nullable.GetUnderlyingType(type);
            //if (IsNullableType(type))
            //{
            //    return type.GetGenericArguments()[0];
            //}
            //return type;
        }
        #endregion
        #region 是否是Enumerable类型
        /// <summary>
        /// 是否是Enumerable类型
        /// <para>eg:TypeHelper.IsEnumerableType(typeof(IEnumerable<string>))==>true</para>
        /// <para>rel:http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html </para>
        /// </summary>
        /// <param name="enumerableType">Type</param>
        /// <returns>是否是Enumerable类型</returns>
        public static bool IsEnumerableType(this Type enumerableType)
        {
            return (FindGenericType(typeof(IEnumerable<>), enumerableType) != null);
        }
        #endregion
        #region 获取IEnumerable类型
        /// <summary>
        /// 获取IEnumerable类型
        /// <para>eg:TypeHelper.GetElementType(typeof(Collection<DateTime>))==>typeof(DateTime)</para>
        /// <para>rel:http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html </para>
        /// </summary>
        /// <param name="enumerableType">Type</param>
        /// <returns>Type</returns>
        public static Type GetElementType(this Type enumerableType)
        {
            Type type = FindGenericType(typeof(IEnumerable<>), enumerableType);
            if (type != null)
            {
                return type.GetGenericArguments()[0];
            }
            return enumerableType;
        }
        #endregion
        #region 是否实现了某泛型接口
        /// <summary>
        /// 是否实现了某泛型接口
        /// <para>eg:TypeHelper.IsKindOfGeneric(typeof(List<string>), typeof(IEnumerable<>))</para>
        /// <para>rel:http://www.cnblogs.com/ldp615/archive/2009/12/11/TypeExtension.html </para>
        /// </summary>
        /// <param name="type">Type</param>
        /// <param name="definition">Type</param>
        /// <returns>是否实现了某泛型接口</returns>
        public static bool IsKindOfGeneric(this Type type, Type definition)
        {
            return (FindGenericType(definition, type) != null);
        }
        #endregion
        #region 私有方法
        private static Type FindGenericType(this Type definition, Type type)
        {
            while ((type != null) && (type != typeof(object)))
            {
                if (type.IsGenericType && (type.GetGenericTypeDefinition() == definition))
                {
                    return type;
                }
                if (definition.IsInterface)
                {
                    foreach (Type type2 in type.GetInterfaces())
                    {
                        Type type3 = FindGenericType(definition, type2);
                        if (type3 != null)
                        {
                            return type3;
                        }
                    }
                }
                type = type.BaseType;
            }
            return null;
        }
        #endregion
    }
}
